﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using GKS.Extensions.String.PatternMatching;
using GKS.Extensions.String.EditDistance;
using GKS.DataTypes.Trees;
using Tests.Math.Numbers;
using Tests.Math;

namespace Tests {
    public class Program {
        private static void PatternMatchingTests() {
            string text = "aabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabba";

            for (int i = 0; i < 100; i++) {
                text += "aabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabba";
            }
            //string text = "aaaaaaab";
            //string text = "aaaaaaaa";
            //string text = "xpbctbxabpqxctbpqtpabxab";
            //string pattern = "aab";
            string pattern = "aabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabbaaabbbabbaaabbaaabbaaabba";// "abbaaabba";
            //string pattern = "aa";
            //string pattern = "tpabxab";
            int[] matchPositions;
            int numberOfComparisons;
            char[] alphabet = (pattern + text).GetAlphabet();
            Stopwatch sw;

            Console.WriteLine("T = \"{0}\"", text);
            Console.WriteLine("P = \"{0}\"", pattern);
            Console.WriteLine("T.Length = {0}", text.Length);
            Console.WriteLine("P.Length = {0}", pattern.Length);
            Console.WriteLine();

            // naive method stats
            sw = Stopwatch.StartNew();
            matchPositions = text.NaivMethod(pattern, out numberOfComparisons);
            sw.Stop();
            Console.WriteLine("Number of matches (Naive Method):\t{0}", matchPositions.Length);
            //Console.Write("Matches:\t\t");

            //foreach (int i in matchPositions) {
            //    Console.Write("{0}\t", i);
            //}

            //Console.WriteLine();
            Console.WriteLine("Number of comparisons:\t{0}", numberOfComparisons);
            Console.WriteLine("Time taken: {0} ms", sw.Elapsed.TotalMilliseconds);
            Console.WriteLine();

            // z algorithm stats
            sw = Stopwatch.StartNew();
            matchPositions = text.ZAlgorithmImplementation(pattern, out numberOfComparisons);
            sw.Stop();
            Console.WriteLine("Number of matches (Z Algorithm):\t{0}", matchPositions.Length);
            //Console.Write("Matches:\t\t");

            //foreach (int i in matchPositions) {
            //    Console.Write("{0}\t", i);
            //}

            //Console.WriteLine();
            Console.WriteLine("Number of comparisons:\t{0}", numberOfComparisons);
            Console.WriteLine("Time taken: {0} ms", sw.Elapsed.TotalMilliseconds); 
            Console.WriteLine();

            // Boyer-Moore algorithm stats
            sw = Stopwatch.StartNew();
            matchPositions = text.BadCharacterShiftRuleImplementation(pattern, alphabet, out numberOfComparisons); //.ZAlgorithmImplementation(pattern, out numberOfComparisons);
            sw.Stop();
            Console.WriteLine("Number of matches (Boyer-Moore Algorithm BCS):\t{0}", matchPositions.Length);
            //Console.Write("Matches:\t\t");

            //foreach (int i in matchPositions) {
            //    Console.Write("{0}\t", i);
            //}

            //Console.WriteLine();
            Console.WriteLine("Number of comparisons:\t{0}", numberOfComparisons);
            Console.WriteLine("Time taken: {0} ms", sw.Elapsed.TotalMilliseconds);
            Console.WriteLine();

            sw = Stopwatch.StartNew();
            matchPositions = text.GoodSuffixRuleImplementation(pattern, alphabet, out numberOfComparisons);//.BadCharacterShiftRuleImplementation(pattern, out numberOfComparisons); //.ZAlgorithmImplementation(pattern, out numberOfComparisons);
            sw.Stop();
            Console.WriteLine("Number of matches (Boyer-Moore Algorithm GS):\t{0}", matchPositions.Length);
            //Console.Write("Matches:\t\t");

            //foreach (int i in matchPositions) {
            //    Console.Write("{0}\t", i);
            //}

            //Console.WriteLine();
            Console.WriteLine("Number of comparisons:\t{0}", numberOfComparisons);
            Console.WriteLine("Time taken: {0} ms", sw.Elapsed.TotalMilliseconds);
            Console.WriteLine();

            // Knuth-Morris-Pratt algorithm stats
            sw = Stopwatch.StartNew();
            matchPositions = text.KnuthMorrisPrattAlgorithmImplementation(pattern, out numberOfComparisons);//.GoodSuffixRuleImplementation(pattern, out numberOfComparisons);//.BadCharacterShiftRuleImplementation(pattern, out numberOfComparisons); //.ZAlgorithmImplementation(pattern, out numberOfComparisons);
            sw.Stop();
            Console.WriteLine("Number of matches (Knuth-Morris-Pratt Algorithm):\t{0}", matchPositions.Length);
            //Console.Write("Matches:\t\t");

            //foreach (int i in matchPositions) {
            //    Console.Write("{0}\t", i);
            //}

            //Console.WriteLine();
            Console.WriteLine("Number of comparisons:\t{0}", numberOfComparisons);
            Console.WriteLine("Time taken: {0} ms", sw.Elapsed.TotalMilliseconds);
            Console.WriteLine();

            //Console.WriteLine();
            Console.ReadKey();
        }

        private static void EditDistanceTests() {
            string first = "vintner";
            string second = "writers";
            int[,] editDistanceMatrix = first.GetEditDistanceMatrix(second);
            int editDistance = first.GetEditDistance(second, editDistanceMatrix);
            string[] transformations = first.GetEditTransformations(second, editDistanceMatrix);

            Console.WriteLine("first = {0}\nsecond = {1}\nedit distance = {2}\nnumber of transformations = {3}", first, second, editDistance, transformations.Length);

            for (int i = 0; i < transformations.Length; i++) {
                Console.WriteLine(transformations[i]);
            }

            Console.ReadKey();
        }

        private static void BSTTests() {
            //string choice = "h";
            //string readElement;
            //int readNumber;
            //int[] path;
            //BinarySearchTree<int> tree = null;

            //do {
            //    Console.Write("(h for help) #> ");
            //    choice = Console.ReadLine();

            //    switch (choice.ToLower()) {
            //        case "h":
            //            Console.WriteLine("\th - help menu");
            //            Console.WriteLine("\ta - add a number");
            //            Console.WriteLine("\ts - search for a number");
            //            Console.WriteLine("\tp - print the tree");
            //            Console.WriteLine("\tr - remove an element from the tree");
            //            Console.WriteLine("\tx - exit");
            //            break;
            //        case "a":
            //            Console.Write("Digit the number you desire:\t");
            //            readElement = Console.ReadLine();
                        
            //            if (int.TryParse(readElement, out readNumber)) {
            //                if (tree == null) {
            //                    tree = new BinarySearchTree<int>(readNumber);

            //                    Console.WriteLine("Number added");
            //                } else {
            //                    if (tree.Add(readNumber, out path)) {
            //                        Console.WriteLine("Number added");

            //                        Console.WriteLine("The path to follow for the added number is: ");
            //                        foreach (int i in path) {
            //                            Console.Write("{0}\t", i);
            //                        }
            //                        Console.WriteLine();
            //                    } else {
            //                        Console.WriteLine("Number not added. Apparently it already existed in the tree.");
            //                    }
            //                }
            //            } else {
            //                Console.WriteLine("This is not a correct integer number. Try again.");
            //            }
                        
            //            break;
            //        case "s":
            //            Console.Write("Digit the number you desire:\t");
            //            readElement = Console.ReadLine();

            //            if (int.TryParse(readElement, out readNumber)) {
            //                if (tree.Search(readNumber, out path)) {
            //                    Console.WriteLine("The desired number was found. The visited numbers are:");

            //                    foreach (int i in path) {
            //                        Console.Write("{0}\t", i);
            //                    }

            //                    Console.WriteLine();
            //                } else {
            //                    Console.WriteLine("Element not found.");
            //                }
            //            } else {
            //                Console.WriteLine("This is not a correct integer number. Try again.");
            //            }

            //            break;
            //        case "p":
            //            tree.Print();
            //            break;
            //        case "r":
            //            Console.Write("Digit the number that you want to remove from the tree:\t");
            //            readElement = Console.ReadLine();

            //            if (int.TryParse(readElement, out readNumber)) {
            //                if (tree.Remove(readNumber)) {
            //                    Console.WriteLine("The number was removed successfully.");
            //                } else {
            //                    Console.WriteLine("The number was not removed from the tree. Probably that number was not in the tree to begin with.");
            //                }
            //            } else {
            //                Console.WriteLine("You must insert a number.");
            //            }
            //            break;
            //        case "x":
            //            break;
            //        default:
            //            Console.WriteLine("Option not available. Available options are:");
            //            choice = "h";
            //            break;
            //    }
            //} while (!choice.ToLower().Equals("x"));
        }
        public static void Main(string[] args) {
            //EditDistanceTests();
            //BSTTests();
            //IntegerNumberTests.TestConstructors();

            //MatrixTest.TestMatrixToString();                // OK
            //MatrixTest.TestMatrixEquality();                // OK
            //MatrixTest.TestMatrixAddition();                // OK
            //MatrixTest.TestMatrixScalarMultiplication();    // OK
            //MatrixTest.TestMatrixTranspose();               // OK
            //MatrixTest.TestMatrixMultiplication();          // OK
            //MatrixTest.TestMatrixTrace();                   // OK
            //MatrixTest.TestMatrixDeterminant();             // OK
            MatrixTest.TestMatrixAsyncAddition();           //

            Console.ReadKey();
        }
    }
}
